package com.cnwidsom.monitor;

import java.beans.IntrospectionException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.bson.BSON;
import org.bson.Document;

import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.util.CycleDetectionStrategy;

import com.cnwidsom.config.MonitorConfig;
import com.cnwidsom.utils.BeanUtils;
import com.cnwidsom.utils.PathUtils;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;

public class MonitorItem implements Serializable {
	private String previousToken;
	private String curToken;
	private List<String> nextToken = new ArrayList<String>();
	private String methodName;
	private String type;
	private long runTime;
	private List<Exception> ex_list;
	private List<String> ex_info = new ArrayList<String>();
	private Map parameters;
	private String name;// 名称,用于显示
	private String nodeName;// 结点名称
	private long recordTime;// 调用完成时间
	private boolean hasException;// 是否发生异常
	private Object extraData;// 自定义数据

	private boolean notRecord;

	// 初始化时计算,用于判断是否需要记录到日志中
	private boolean needRecord = false;
	private transient MonitorConfig.MonitorItemConfig mic;

	public MonitorItem() {

	}

	public MonitorItem(Token token, String methodName, long runTime, List ex_list, long recordTime, Object extraData) {
		if (token != null) {
			if (token.getPreviousToken() != null)
				this.previousToken = token.getPreviousToken().getCurTokenValue();
			if (token.getNextToken() != null) {
				for (Token nToken : token.getNextToken()) {
					this.nextToken.add(nToken.getCurTokenValue());
				}
			}
			this.curToken = token.getCurTokenValue();
			this.methodName = methodName;
			this.runTime = runTime;
			this.ex_list = ex_list;
			this.name = token.getName();
			this.nodeName = MonitorConfig.getCur_mc().getNodeName();
			// this.recordTime = recordTime;
			this.recordTime = token.getStartTime();
			this.extraData = extraData;
			this.notRecord = token.isNotRecord();

			boolean isRecordExceptionDetail = MonitorConfig.getCur_mc().isDefaultRecordExceptionDetail();
			long m_recordTime = MonitorConfig.getCur_mc().getDefaultRecordTime();
			int forceRecord = MonitorConfig.getCur_mc().getDefaultForceRecord();
			mic = MonitorConfig.getCur_mc().getMatchRule(PathUtils.getMethodClassName(methodName));
			if (mic != null) {
				if (mic.isRecordExceptionDetail() != null)
					isRecordExceptionDetail = mic.isRecordExceptionDetail();
				if (mic.getRecordTime() != null)
					m_recordTime = mic.getRecordTime();
				if (mic.getForceRecord() != null)
					forceRecord = mic.getForceRecord();
			}

			// 强制记录
			if (forceRecord == MonitorConfig.RECORD_TYPE_FORCE) {
				needRecord = true;
			}
			if (isRecordExceptionDetail) {
				for (Object ex : ex_list) {
					// 如果发生异常,进行记录
					needRecord = true;
					ex_info.add(((Exception) ex).getMessage());
					for (StackTraceElement elem : ((Exception) ex).getStackTrace()) {
						ex_info.add(elem.toString());
					}
				}
			}

			if (ex_list != null && ex_list.size() > 0)
				hasException = true;
			else
				hasException = false;

			
			// 如果执行超时,记录
			if (runTime >= m_recordTime) {
				needRecord = true;
			}
			switch (token.getType()) {
			case Token.TYPE_START_CALL:
				this.type = "TYPE_START_CALL";
				break;
			case Token.TYPE_NONSTART_CALL:
				this.type = "TYPE_NONSTART_CALL";
				break;
			case Token.TYPE_CALLED:
				this.type = "TYPE_CALLED";
				break;
			case Token.TYPE_DISTRIBUTE_CALLED:
				this.type = "TYPE_DISTRIBUTE_CALLED";
				break;
			case Token.TYPE_DISTRIBUTE_CALL:
				this.type = "TYPE_DISTRIBUTE_CALL";
				break;
			case Token.TYPE_DB_CALLED:
				this.type = "TYPE_DB_CALLED";
				break;
			default:
				this.type = "UNKNOWN_TYPE";
			}
		} else {
			notRecord = true;
		}
	}

	public String getPreviousToken() {
		return previousToken;
	}

	public void setPreviousToken(String previousToken) {
		this.previousToken = previousToken;
	}

	public String getCurToken() {
		return curToken;
	}

	public void setCurToken(String curToken) {
		this.curToken = curToken;
	}

	public List<String> getNextToken() {
		return nextToken;
	}

	public void setNextToken(List<String> nextToken) {
		this.nextToken = nextToken;
	}

	public String getMethodName() {
		return methodName;
	}

	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}

	public long getRunTime() {
		return runTime;
	}

	public void setRunTime(long runTime) {
		this.runTime = runTime;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public List<String> getEx_info() {
		return ex_info;
	}

	public void setEx_info(List<String> ex_info) {
		this.ex_info = ex_info;
	}

	public Map getParameters() {
		return parameters;
	}

	public boolean isNeedRecord() {
		return needRecord;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getNodeName() {
		return nodeName;
	}

	public long getRecordTime() {
		return recordTime;
	}

	public boolean isHasException() {
		return hasException;
	}

	public void setHasException(boolean hasException) {
		this.hasException = hasException;
	}

	public Object getExtraData() {
		return extraData;
	}

	public void setExtraData(Object extraData) {
		this.extraData = extraData;
	}

	public boolean isNotRecord() {
		return notRecord;
	}

	public void setParameters(Map parameters) {
		String isRecordParameters = MonitorConfig.getCur_mc().getIsDefaultRecordParameters();
		if (mic != null) {
			if (mic.isRecordExceptionDetail() != null)
				isRecordParameters = mic.getIsRecordParameters();
		}
		if (isRecordParameters.equalsIgnoreCase(MonitorConfig.RECORD_PARAMETERS_TYPE_ALWAYS)
				|| (isRecordParameters.equalsIgnoreCase(MonitorConfig.RECORD_PARAMETERS_TYPE_WITHERROR) && ex_list != null && ex_list.size() > 0)) {
			this.parameters = parameters;
		} else {
			this.parameters = null;
		}
	}

	public String toJsonString() {
		JsonConfig jsonConfig = new JsonConfig();
		jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
		jsonConfig.setIgnoreDefaultExcludes(false); // 设置默认忽略
		// 忽略没有值的字段
		String ignoreField = "needRecord,notRecord";
		if (parameters == null)
			ignoreField += ",parameters";
		if (ex_info == null || ex_info.size() == 0)
			ignoreField += ",ex_info";
		jsonConfig.setExcludes(ignoreField.split(","));

		JSONObject json = null;
		try {// 有的Parameter会影响JSON序列化,此处会检测当前MonitorItem是否可以序列化,如果不可以会删除Parameter再试一次
			json = JSONObject.fromObject(this, jsonConfig);
		} catch (JSONException ex) {
			Map param = new HashMap(this.getParameters());
			this.setParameters(null);
			try {
				json = JSONObject.fromObject(this, jsonConfig);
			} catch (JSONException ex2) {
				throw ex2;
			} finally {
				this.setParameters(param);
			}
		}
		return json.toString();
	}

	public Document toDocument() throws IllegalAccessException, InvocationTargetException, IntrospectionException {

		DBObject dbObj = (DBObject) JSON.parse(toJsonString());
		// Map map = BeanUtils.toMap(this);
		if (parameters == null)
			dbObj.removeField("parameters");
		if (ex_info == null || ex_info.size() == 0)
			dbObj.removeField("ex_info");
		if (extraData == null)
			dbObj.removeField("extraData");
		Document doc = new Document();
		doc.putAll(dbObj.toMap());

		return doc;
	}
}
